﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2013  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#include "opengles.h"
#include "../OS/OSTypes.h"
#include "../OS/OS.h"

#if 0 //def _UXS_USE_OPENGLES


namespace UX_STL
{
namespace UXTypesExt
{
/*
=================================================
	очистить стэк ошибок
=================================================
*/
	void TAPIErrorChecker::ClearGLErrors()
	{
		for (uint i = 0; i < uMaxErrors && gles::glGetError() != gles::GL_NO_ERROR; ++i) {}
	}
	
/*
=================================================
	проверить не было ли ошибки
=================================================
*/
	bool TAPIErrorChecker::CheckGLError(const char *pGLFunc, const char *pFunc, const char *pFile, uint uLine)
	{
		gles::GLenum	err = gles::glGetError();
		string			str( "OpenGL error: " );

		if ( err == gles::GL_NO_ERROR )
			return true;

		switch ( err )
		{
			case gles::GL_INVALID_ENUM:
				str << "GL_INVALID_ENUM";
				break;

			case gles::GL_INVALID_VALUE:
				str << "GL_INVALID_VALUE";
				break;

			case gles::GL_INVALID_OPERATION:
				str << "GL_INVALID_OPERATION";
				break;

			case gles::GL_INVALID_FRAMEBUFFER_OPERATION:
				str << "GL_INVALID_FRAMEBUFFER_OPERATION";
				break;

			case gles::GL_OUT_OF_MEMORY:
				str << "GL_OUT_OF_MEMORY";
				break;

			default:
				str << "code 0x" << string().FormatI( err, 16 );
				break;
		}

		str << ", in " << pGLFunc;
		str << ", function: " << pFunc;

		LOG_EXT( str.cstr(), e_log_msg::ERROR_2, pFile, uLine );
		return false;
	}
	
/*
=================================================
	проверить не было ли ошибок
=================================================
*/
	bool TAPIErrorChecker::CheckGLErrors(const char *pFile, uint uLine)
	{
		gles::GLenum	err;
		bool			ret = true;

		for (uint i = 0; i < uMaxErrors && (err = gles::glGetError()) != gles::GL_NO_ERROR; ++i)
		{
			string	str( "OpenGL error: " );

			switch ( err )
			{
				case gles::GL_INVALID_ENUM:
					str << "GL_INVALID_ENUM";
					break;

				case gles::GL_INVALID_VALUE:
					str << "GL_INVALID_VALUE";
					break;

				case gles::GL_INVALID_OPERATION:
					str << "GL_INVALID_OPERATION";
					break;

				case gles::GL_INVALID_FRAMEBUFFER_OPERATION:
					str << "GL_INVALID_FRAMEBUFFER_OPERATION";
					break;

				case gles::GL_OUT_OF_MEMORY:
					str << "GL_OUT_OF_MEMORY";
					break;

				default:
					str << "code 0x" << string().FormatI( err, 16 );
					break;
			}

			LOG_EXT( str.cstr(), e_log_msg::ERROR_2, pFile, uLine );
			ret = false;
		}

		return ret;
	}

}	// UXTypesExt
}	// UX_STL



namespace gles
{
	using namespace UX_STL;


#ifdef PLATFORM_WINDOWS

#	define OPENGLES_LIBRARY						"opengl32.dll"
#	define GLES_GETPROCADDRESS( _address )		s_pGetProcAddress( (winapi::LPCSTR)_address )
//#	define GLES_GETPROCADDRESS_CORE( _address )	s_sLibOpenGL.GetProc( _address )

//	typedef winapi::PROC (CALLBACK *PFNwglGetProcAddressProc_t) (winapi::LPCSTR lpszProc);

	static UXTypesExt::TLibrary					s_sLibOpenGL;
//	static PFNwglGetProcAddressProc_t			s_pGetProcAddress = null;

#endif



#ifdef PLATFORM_LINUX
#	define GLES_GETPROCADDRESS( _address )		glXGetProcAddress( (const GLubyte *)_address )
#	error TODO...
#endif


#ifdef PLATFORM_ANDROID
	
#	define OPENGLES_LIBRARY						"libGLESv2.so"
#	define GLES_GETPROCADDRESS( _address )		s_sLibOpenGL.GetProc( _address )
//#	define GLES_GETPROCADDRESS_CORE( _address )	s_sLibOpenGL.GetProc( _address )

	static UXTypesExt::TLibrary					s_sLibOpenGL;

#endif


#ifndef GLES_GETPROCADDRESS
#	error not defined "*GetProcAddress" function!
#endif



#ifdef GLES_EMULATE
#	define GLES_SWITCH( _gles, _gl )	_gl
#else
#	define GLES_SWITCH( _gles, _gl )	_gles
#endif

	
// получить адрес функции из драйвера
#define OPENGLES_GET_PROC( p, n, d ) \
	if ( (n = (p)GLES_GETPROCADDRESS( #n ))			== null ) \
	if ( (n = (p)GLES_GETPROCADDRESS( #n"EXT" ))	== null ) \
	if ( (n = (p)GLES_GETPROCADDRESS( #n"OES" ))	== null ) \
	/*if ( (n = (p)GLES_GETPROCADDRESS_CORE( #n ))	== null )*/ \
	{ \
		n = d; \
		ret &= GL_FALSE; \
	}

	
// Default Functions //
#undef  GLES_BUILD_DEFFUNC
#define GLES_BUILD_DEFFUNC( _retType, _funcName, _funcParams, _retValue ) \
	GL_APICALL _retType GL_APIENTRY glDefault##_funcName _funcParams \
	{ \
		ASSERT_EXT( false, #_funcName ); \
		return _retValue; \
	}
	
// pointers to functions //
#undef  GLES_BUILDFUNC
#define GLES_BUILDFUNC( _retType, _funcName, _funcParams, _retValue ) \
	PFNGL##_funcName##PROC	gl##_funcName = null;
	
// constants //
#undef  GLES_BUILDCONST
#define GLES_BUILDCONST( _type, _name ) \
	_type	C_GL_##_name = _type();



	GLES_CORE_FUNCTIONS( GLES_BUILD_DEFFUNC )
	GLES_CORE_FUNCTIONS( GLES_BUILDFUNC )
	GLES_CONSTANTS_I( GLES_BUILDCONST )
			
	namespace OES_get_program_binary {
		GLES_GET_PROGRAM_BINARY( GLES_BUILD_DEFFUNC )
		GLES_GET_PROGRAM_BINARY( GLES_BUILDFUNC )
	}
	namespace OES_texture_3D {
		GLES_TEXTURE_3D( GLES_BUILD_DEFFUNC )
		GLES_TEXTURE_3D( GLES_BUILDFUNC )
		GLES_BUILDCONST( GLint, MAX_3D_TEXTURE_SIZE )
	}
	namespace OES_vertex_array_object {
		GLES_VERTEX_ARRAY_OBJECT( GLES_BUILD_DEFFUNC )
		GLES_VERTEX_ARRAY_OBJECT( GLES_BUILDFUNC )
	}
	namespace EXT_debug_label {
		GLES_DEBUG_LABEL( GLES_BUILD_DEFFUNC )
		GLES_DEBUG_LABEL( GLES_BUILDFUNC )
	}
	namespace EXT_debug_marker {
		GLES_DEBUG_MARKER( GLES_BUILD_DEFFUNC )
		GLES_DEBUG_MARKER( GLES_BUILDFUNC )
	}
	namespace EXT_discard_framebuffer {
		GLES_DISCARD_FRAMEBUFFER( GLES_BUILD_DEFFUNC )
		GLES_DISCARD_FRAMEBUFFER( GLES_BUILDFUNC )
	}
	namespace EXT_multisampled_render_to_texture {
		GLES_MULTISAMPLED_RENDER_TO_TEXTURE( GLES_BUILD_DEFFUNC )
		GLES_MULTISAMPLED_RENDER_TO_TEXTURE( GLES_BUILDFUNC )
		GLES_BUILDCONST( GLint, MAX_SAMPLES )
	}
	namespace EXT_multi_draw_arrays {
		GLES_MULTI_DRAW_ARRAYS( GLES_BUILD_DEFFUNC )
		GLES_MULTI_DRAW_ARRAYS( GLES_BUILDFUNC )
	}
	namespace EXT_occlusion_query_boolean {
		GLES_OCCLUSION_QUERY_BOOLEAN( GLES_BUILD_DEFFUNC )
		GLES_OCCLUSION_QUERY_BOOLEAN( GLES_BUILDFUNC )
	}
	namespace EXT_robustness {
		GLES_ROBUSTNESS( GLES_BUILD_DEFFUNC )
		GLES_ROBUSTNESS( GLES_BUILDFUNC )
	}
	namespace EXT_separate_shader_objects {
		GLES_SEPARATE_SHADER_OBJECTS( GLES_BUILD_DEFFUNC )
		GLES_SEPARATE_SHADER_OBJECTS( GLES_BUILDFUNC )
	}
	namespace EXT_texture_storage {
		GLES_TEXTURE_STORAGE( GLES_BUILD_DEFFUNC )
		GLES_TEXTURE_STORAGE( GLES_BUILDFUNC )
	}
	namespace EXT_texture_filter_anisotropic {
		GLES_BUILDCONST( GLint, MAX_TEXTURE_MAX_ANISOTROPY )
	}



	void _ClearExtensions();
	
/*
=================================================
	инициализация библиотеки
=================================================
*/
	bool _InitLibrary()
	{
		bool	res = true;
		
		res &= s_sLibOpenGL.Load( OPENGLES_LIBRARY );

//#	if PLATFORM_WINDOWS
//		res &= s_sLibOpenGL.GetProc( s_pGetProcAddress, "wglGetProcAddress" );
//#	endif

		return res;
	}

/*
=================================================
	очистить стэк ошибок
=================================================
*/
	GLES_API void GLES_ClearErrors(int maxErros)
	{
		for (int i = 0; i < maxErros && glGetError() != GL_NO_ERROR; ++i) {}
	}
	
/*
=================================================
	проверить не было ли ошибок
=================================================
*/
	GLES_API bool GLES_CheckErrors(int maxErrors)
	{
		GLenum	err;
		bool	ret = true;

		for (int i = 0; i < maxErrors && (err = glGetError()) != GL_NO_ERROR; ++i)
		{
			ret = false;
		}

		return ret;
	}

/*
=================================================
	проверка поддерживается ли расширение
=================================================
*/
	static UXTypes::uni_c_string	s_sExtensions;

	bool _IsExtSupported(const char *pName)
	{
		if ( s_sExtensions.Empty() )
			s_sExtensions = UXTypes::uni_c_string( (const char *) glGetString( GL_EXTENSIONS ) );

		UXTypes::usize	pos = 0;
		return s_sExtensions.Find( pName, pos, 0 );
	}

/*
=================================================
	инициализация
=================================================
*/
	GLES_API bool GLES_Init()
	{
		GLboolean	ret = GL_TRUE;

		if ( _InitLibrary() )
			return false;
		
		// CORE FUNCTIONS //
		#define GLES_GETPROC( _retType, _funcName, _funcParams, _retValue ) \
			OPENGLES_GET_PROC( PFNGL##_funcName##PROC,	gl##_funcName,	&glDefault##_funcName );

		#undef  GLES_GETCONST
		#define GLES_GETCONST( _type, _name ) \
			glGetIntegerv( GL_##_name, &C_GL_##_name );

		#define GLES_INIT_EXT_CONST( _namespace, _name ) \
			if ( _namespace::IsSupported() ) \
				glGetIntegerv( _namespace::GL_##_name, &_namespace::C_GL_##_name ); \

		GLES_CORE_FUNCTIONS( GLES_GETPROC )
		
		OES_get_program_binary::UnloadExtension();
		OES_texture_3D::UnloadExtension();
		OES_vertex_array_object::UnloadExtension();
		EXT_debug_label::UnloadExtension();
		EXT_debug_marker::UnloadExtension();
		EXT_discard_framebuffer::UnloadExtension();
		EXT_multisampled_render_to_texture::UnloadExtension();
		EXT_multi_draw_arrays::UnloadExtension();
		EXT_occlusion_query_boolean::UnloadExtension();
		EXT_robustness::UnloadExtension();
		EXT_separate_shader_objects::UnloadExtension();
		EXT_texture_storage::UnloadExtension();
		
		_ClearExtensions();

		// init extensions constants //
		GLES_CONSTANTS_I( GLES_GETCONST )

		return !!ret;
	}
	
/*
=================================================
	обнуляет адреса функций
=================================================
*/
	GLES_API void GLES_Delete()
	{
		// CORE FUNCTIONS //
		#define GLES_ZEROFUNC( _retType, _funcName, _funcParams, _retValue ) \
			gl##_funcName = &glDefault##_funcName;

		GLES_CORE_FUNCTIONS( GLES_ZEROFUNC )
				
		OES_get_program_binary::UnloadExtension();
		OES_texture_3D::UnloadExtension();
		OES_vertex_array_object::UnloadExtension();
		EXT_debug_label::UnloadExtension();
		EXT_debug_marker::UnloadExtension();
		EXT_discard_framebuffer::UnloadExtension();
		EXT_multisampled_render_to_texture::UnloadExtension();
		EXT_multi_draw_arrays::UnloadExtension();
		EXT_occlusion_query_boolean::UnloadExtension();
		EXT_robustness::UnloadExtension();
		EXT_separate_shader_objects::UnloadExtension();
		EXT_texture_storage::UnloadExtension();

		_ClearExtensions();
	}

/*
=================================================
	инициализация расширений
=================================================
*/
#	define _IS_SUPPORTED( _name ) \
		_IsExtSupported( "GL_"#_name )

#	define GLES_CHECK_SUPPORTED( _name, _gl_name ) \
		namespace _name { \
			\
			static int	s_iExtension_##_name = 0; \
			\
			GLES_API bool IsSupported() \
			{ \
				if ( s_iExtension_##_name == 0 ) \
					s_iExtension_##_name = _IS_SUPPORTED( GLES_SWITCH( _name, _gl_name ) ) + 1; \
				\
				return s_iExtension_##_name == 2; \
			} \
		}

#	define GLES_INIT_EXTENSION( _name, _gl_name, _funcs ) \
		GLES_CHECK_SUPPORTED( _name, _gl_name ) \
		namespace _name { \
		\
			GLES_API bool LoadExtension() \
			{ \
				GLboolean	ret = GL_TRUE; \
				_funcs( GLES_GETPROC ) \
				return !!ret; \
			} \
			\
			GLES_API void UnloadExtension() \
			{ \
				_funcs( GLES_ZEROFUNC ) \
				s_iExtension_##_name = 0; \
			} \
		}



	GLES_CHECK_SUPPORTED( OES_compressed_ETC1_RGB8_texture, UNKNOWN )
	GLES_CHECK_SUPPORTED( OES_compressed_paletted_texture, UNKNOWN )
	GLES_CHECK_SUPPORTED( OES_depth24, VERSION_1_1 )
	GLES_CHECK_SUPPORTED( OES_depth32, VERSION_3_0 )
	GLES_CHECK_SUPPORTED( OES_element_index_uint, VERSION_2_0 )
	GLES_INIT_EXTENSION(  OES_get_program_binary, ARB_get_program_binary, GLES_GET_PROGRAM_BINARY )
	GLES_CHECK_SUPPORTED( OES_mapbuffer, VERSION_2_0 )
	GLES_CHECK_SUPPORTED( OES_packed_depth_stencil, EXT_packed_depth_stencil )
	GLES_CHECK_SUPPORTED( OES_rgb8_rgba8, VERSION_2_0 )
	GLES_CHECK_SUPPORTED( OES_standard_derivatives, UNKNOWN )
	GLES_CHECK_SUPPORTED( OES_stencil1, VERSION_2_0 )
	GLES_CHECK_SUPPORTED( OES_stencil4, VERSION_2_0 )
	GLES_INIT_EXTENSION(  OES_texture_3D, EXT_texture_3D,  GLES_TEXTURE_3D )
	GLES_CHECK_SUPPORTED( OES_texture_half_float, ARB_half_float_pixel )
	GLES_CHECK_SUPPORTED( OES_vertex_half_float, VERSION_2_0 )
	GLES_INIT_EXTENSION(  OES_vertex_array_object, ARB_vertex_array_object,  GLES_VERTEX_ARRAY_OBJECT )
	GLES_CHECK_SUPPORTED( OES_vertex_type_10_10_10_2, ARB_vertex_type_2_10_10_10_rev )
	GLES_CHECK_SUPPORTED( EXT_blend_minmax, EXT_blend_minmax )
	GLES_CHECK_SUPPORTED( EXT_color_buffer_half_float, ARB_half_float_pixel )
	GLES_INIT_EXTENSION(  EXT_debug_label, ARB_debug_label, GLES_DEBUG_LABEL )
	GLES_INIT_EXTENSION(  EXT_debug_marker, UNKNOWN,  GLES_DEBUG_MARKER )
	GLES_INIT_EXTENSION(  EXT_discard_framebuffer, UNKNOWN, GLES_DISCARD_FRAMEBUFFER )
	GLES_INIT_EXTENSION(  EXT_multisampled_render_to_texture, EXT_framebuffer_multisample, GLES_MULTISAMPLED_RENDER_TO_TEXTURE )
	GLES_INIT_EXTENSION(  EXT_multi_draw_arrays, VERSION_2_0,  GLES_MULTI_DRAW_ARRAYS )
	GLES_INIT_EXTENSION(  EXT_occlusion_query_boolean, ARB_occlusion_query,  GLES_OCCLUSION_QUERY_BOOLEAN )
	GLES_CHECK_SUPPORTED( EXT_read_format_bgra, VERSION_2_0 )
	GLES_INIT_EXTENSION(  EXT_robustness, UNKNOWN, GLES_ROBUSTNESS )
	GLES_INIT_EXTENSION(  EXT_separate_shader_objects, ARB_separate_shader_objects,  GLES_SEPARATE_SHADER_OBJECTS )
	GLES_CHECK_SUPPORTED( EXT_shadow_samplers, ARB_shadow )
	GLES_CHECK_SUPPORTED( EXT_sRGB, ARB_framebuffer_sRGB  )
	GLES_CHECK_SUPPORTED( EXT_texture_compression_dxt1, EXT_texture_compression_dxt1 )
	GLES_CHECK_SUPPORTED( EXT_texture_filter_anisotropic, EXT_texture_filter_anisotropic )
	GLES_CHECK_SUPPORTED( EXT_texture_format_BGRA8888, EXT_bgra )
	GLES_CHECK_SUPPORTED( EXT_texture_rg, ARB_texture_rg )
	GLES_INIT_EXTENSION(  EXT_texture_storage, ARB_texture_storage,  GLES_TEXTURE_STORAGE )
	GLES_CHECK_SUPPORTED( EXT_frag_depth, VERSION_2_0 )
	GLES_CHECK_SUPPORTED( OES_fragment_precision_high, VERSION_2_0 )
	
/*
=================================================
	сбрасываются значения констант
=================================================
*/
#	define GLES_CLEAR_EXTENSION( _name ) \
		_name::s_iExtension_##_name = 0;

	void _ClearExtensions()
	{
		GLES_CLEAR_EXTENSION( OES_compressed_ETC1_RGB8_texture )
		GLES_CLEAR_EXTENSION( OES_compressed_paletted_texture )
		GLES_CLEAR_EXTENSION( OES_depth24 )
		GLES_CLEAR_EXTENSION( OES_depth32 )
		GLES_CLEAR_EXTENSION( OES_element_index_uint )
		GLES_CLEAR_EXTENSION( OES_mapbuffer )
		GLES_CLEAR_EXTENSION( OES_packed_depth_stencil )
		GLES_CLEAR_EXTENSION( OES_rgb8_rgba8 )
		GLES_CLEAR_EXTENSION( OES_standard_derivatives )
		GLES_CLEAR_EXTENSION( OES_stencil1 )
		GLES_CLEAR_EXTENSION( OES_stencil4 )
		GLES_CLEAR_EXTENSION( OES_texture_half_float )
		GLES_CLEAR_EXTENSION( OES_vertex_half_float )
		GLES_CLEAR_EXTENSION( OES_vertex_type_10_10_10_2 )
		GLES_CLEAR_EXTENSION( EXT_blend_minmax )
		GLES_CLEAR_EXTENSION( EXT_color_buffer_half_float )
		GLES_CLEAR_EXTENSION( EXT_read_format_bgra )
		GLES_CLEAR_EXTENSION( EXT_shadow_samplers )
		GLES_CLEAR_EXTENSION( EXT_sRGB )
		GLES_CLEAR_EXTENSION( EXT_texture_compression_dxt1 )
		GLES_CLEAR_EXTENSION( EXT_texture_filter_anisotropic )
		GLES_CLEAR_EXTENSION( EXT_texture_format_BGRA8888 )
		GLES_CLEAR_EXTENSION( EXT_texture_rg )
		GLES_CLEAR_EXTENSION( EXT_texture_storage )
		GLES_CLEAR_EXTENSION( EXT_frag_depth )
		GLES_CLEAR_EXTENSION( OES_fragment_precision_high )
		
		#define GLES_CLEAR_EXT_CONST( _namespace, _name, _type ) \
			_namespace::C_GL_##_name = _type();
		
		GLES_CLEAR_EXT_CONST(  OES_texture_3D,  MAX_3D_TEXTURE_SIZE,  GLint )
		GLES_CLEAR_EXT_CONST(  EXT_multisampled_render_to_texture,  MAX_SAMPLES,  GLint )
		GLES_CLEAR_EXT_CONST(  EXT_texture_filter_anisotropic,  MAX_TEXTURE_MAX_ANISOTROPY,  GLint )
	}
	
//-------------------------------------------------------------------

}	// gles

#endif	// _UXS_USE_OPENGLES
